/**
 * Copyright (c) 2016 Lenovo Group
 * All Rights Reserved.
 * 
 * Project Name:app-gateway
 * Create Time: 2016年1月21日 下午2:15:48
 */
package com.lenovo.lmrp.server.appgateway.spi;

import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Part;
import javax.ws.rs.Consumes;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.container.AsyncResponse;
import javax.ws.rs.core.Response;

import org.jboss.resteasy.annotations.GZIP;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.lenovo.lmrp.api.appgateway.IAppTicket;
import com.lenovo.lmrp.api.assigntrace.ITraceTicket;
import com.lenovo.lmrp.api.constant.TicketAction;
import com.lenovo.lmrp.api.itsmgateway.IItsmTicket;
import com.lenovo.lmrp.api.model.RestResponse;
import com.lenovo.lmrp.api.model.entity.AttachmentPO;
import com.lenovo.lmrp.api.model.view.AttachmentUploadVO;
import com.lenovo.lmrp.api.model.view.AttachmentVO;
import com.lenovo.lmrp.api.model.view.ChangedTicketVO;
import com.lenovo.lmrp.api.model.view.GrabRecode;
import com.lenovo.lmrp.api.model.view.SearchListFilter;
import com.lenovo.lmrp.api.model.view.TicketTotalVO;
import com.lenovo.lmrp.api.model.view.TicketVO;
import com.lenovo.lmrp.base.FTPService;
import com.lenovo.lmrp.base.FileSystemService;
import com.lenovo.lmrp.base.IFileService;
import com.lenovo.lmrp.base.mq.MQAppGatewayEvent;
import com.lenovo.lmrp.base.mq.MQContent;
import com.lenovo.lmrp.base.mq.MQTopic;
import com.lenovo.lmrp.server.appgateway.AppSession;
import com.lenovo.lmrp.server.appgateway.RestClientFactory;
import com.lenovo.lmrp.server.appgateway.util.AppCache;
import com.lenovo.lmrp.server.appgateway.util.AppMQClient;
import com.lenovo.lmrp.server.appgateway.util.PropertiesUtil;
import com.lenovo.sdc.framework.annotation.RestService;
import com.lenovo.sdc.framework.cache.CacheItem;
import com.lenovo.sdc.framework.rest.RestClientProxy;
import com.lenovo.sdc.framework.util.CommonUtil;
import com.lenovo.sdc.framework.util.JSONHelper;
import com.lenovo.sdc.framework.util.Tuple;
import com.lenovo.sdc.framework.util.exception.ErrorCode;
import com.lenovo.sdc.framework.util.exception.TraceableException;

/**
 * @author zhangzhenga
 *
 */
@RestService
@Path("/app/v1")
@GZIP
@Produces("application/json;charset-utf-8")
@Consumes("application/json;charset-utf-8")
public class AppTicketImpl implements IAppTicket {

    private static final Logger log = LoggerFactory.getLogger(AppTicketImpl.class);

    private String token;
    private AppSession appsession;

    @HeaderParam("Authorization")
    private void setToken(String authorization) {
        if (!CommonUtil.isNullOrEmpty(authorization)) {
            this.token = authorization.substring(6);
            CacheItem<AppSession> cache = AppCache.getClient().get(AppSession.class, token);
            appsession = cache.getValue();
        }
    }

    private ThreadPoolExecutor executorPool = new ThreadPoolExecutor(4, 8, 30, TimeUnit.MINUTES,
        new LinkedBlockingQueue<Runnable>());

    @Override
    public RestResponse<List<TicketVO>> getTicketList(String itsmcode, SearchListFilter filter) {
        //调用Trace接口
        RestClientProxy clientProxy = RestClientFactory.getAssignTraceClient();
        ITraceTicket traceTicket = clientProxy.getService(ITraceTicket.class);
        filter.setEngineer(appsession == null ? "" : appsession.getLoginData().getLoginname());
        RestResponse<List<TicketVO>> tickets = traceTicket.getEntityList(itsmcode, "ticket", filter);
        return tickets;
    }

    /* (non-Javadoc)
     * @see com.lenovo.lmrp.api.appgateway.IAppTicket#getTicket(java.lang.String, java.lang.String)
     */
    @Override
    public RestResponse<TicketVO> getTicket(String itsmcode, String ticketid) {
        // TODO Auto-generated method stub
        return null;
    }

    /* (non-Javadoc)
     * @see com.lenovo.lmrp.api.appgateway.IAppTicket#updateTicket(java.lang.String, java.lang.String, java.lang.String, com.lenovo.lmrp.api.model.view.ChangedTicketVO)
     */
    @Override
    public RestResponse<String> updateTicket(String itsmcode, String ticketid, String action, ChangedTicketVO ticket) {
        log.debug("appgateway update ticket {}, action {} start", ticketid, action);
        RestResponse<String> response = null;
        try {
            //获取当前操作工程师
            String engineer = appsession == null ? "" : appsession.getLoginData().getLoginname();

            TicketAction ticketAction = TicketAction.valueOf(action.toUpperCase());
            //发送MQ消息 通知trace工程师抢单
            if (ticketAction == TicketAction.GRAB) {
                MQContent mqc = new MQContent();
                mqc.setItsmcode(itsmcode);
                mqc.setSource(MQTopic.APPGWEVENT.getSource());
                mqc.setEvent(MQAppGatewayEvent.GRAB.getEvent());

                GrabRecode recode = new GrabRecode();
                recode.setEngineerId(engineer);
                recode.setTicketId(ticketid);
                mqc.setContent(recode);

                AppMQClient.getMQClient().publish(MQTopic.APPGWEVENT.name(), JSONHelper.toJSON(mqc));
                response = new RestResponse<String>(0, "ok", null);
            }
            else {
                //调用Trace更新工单信息接口
                RestClientProxy clientProxy = RestClientFactory.getAssignTraceClient();
                ITraceTicket traceTicket = clientProxy.getService(ITraceTicket.class);
                Map<String, String> files = ticket.getFields();
                if (Objects.isNull(files)) {
                    files = new HashMap<>();
                }
                if (ticketAction == TicketAction.CONFIRM) {
                    files.put("assigneeloginname", engineer);
                }
                response = traceTicket.updateTicket(itsmcode, ticketid, action.toLowerCase(), files);
            }
        }
        catch (Exception exp) {
            log.error("appgateway error when update ticketid = {}, operate = {}", action, ticketid, exp);
            response = new RestResponse<String>(1, "工单处理失败,请联系管理员!", null);
        }
        log.debug("appgateway update ticket {}, action {} end", ticketid, action);
        return response;
    }

    /* (non-Javadoc)
     * @see com.lenovo.lmrp.api.appgateway.IAppTicket#getTicketTotal(java.lang.String)
     */
    @Override
    public RestResponse<TicketTotalVO> getTicketTotal(String itsmcode) {
        //调用Trace接口
        RestClientProxy clientProxy = RestClientFactory.getAssignTraceClient();
        ITraceTicket traceTicket = clientProxy.getService(ITraceTicket.class);
        //获取当前操作工程师
        RestResponse<TicketTotalVO> response = traceTicket.getEntityTotal(itsmcode, "ticket",
            appsession == null ? "" : appsession.getLoginData().getLoginname());
        return response;
    }

    /* (non-Javadoc)
     * @see com.lenovo.lmrp.api.appgateway.IAppTicket#getTicketGrabResult(java.lang.String, java.lang.String)
     */
    @Override
    public RestResponse<Object> getGrabResult(String itsmcode, String ticketid) {
        //调用Trace接口
        RestClientProxy clientProxy = RestClientFactory.getAssignTraceClient();
        ITraceTicket traceTicket = clientProxy.getService(ITraceTicket.class);

        RestResponse<Object> response = traceTicket.getGrabResult(itsmcode,
            appsession == null ? "" : appsession.getLoginData().getLoginname(), ticketid);
        return response;
    }

    /**
     * 保存附件信息
     * @see com.lenovo.lmrp.api.appgateway.IAppTicket#createAttachment(java.lang.String, java.lang.String, com.lenovo.lmrp.api.model.view.AttachmentVO)
     */
    @Override
    public RestResponse<List<String>> createAttachment(String itsmcode, String ticketid,
                                                       AttachmentUploadVO attachmentUploadVO) {
        RestClientProxy clientProxy = RestClientFactory.getItsmGatewayClient();
        IItsmTicket itsmTicket = clientProxy.getService(IItsmTicket.class);
        List<String> idList = new LinkedList<String>();
        for (String original : attachmentUploadVO.getOriginal()) {
            //附件路径和附件类型用 | 分割
            String[] splits = original.split("\\?");
            String filePath = splits[0];
            //默认文件类型 其他
            int attachmentType = 1;
            if (splits.length > 1) {
                attachmentType = Integer.parseInt(splits[1]);
            }
            String engnieer = appsession == null ? "" : appsession.getLoginData().getLoginname();

            AttachmentVO attVO = new AttachmentVO();
            attVO.setName(filePath.substring(filePath.lastIndexOf("/") + 1));
            attVO.setOriginal(filePath);
            attVO.setStatus(AttachmentPO.AttachmentStatus.UNUPLOADED.ordinal());
            attVO.setType(attachmentType);
            attVO.setSubmitter(engnieer);
            RestResponse<String> result = itsmTicket.createAttachment(itsmcode, ticketid, attVO);
            idList.add(result.getResult());
        }
        return new RestResponse<List<String>>(0, "OK", idList);
    }

    /**
     * 上传附件流
     */
    @Override
    public void uploadAttachment(String itsmcode, String ticketid, String attachmentid, HttpServletRequest request,
                                 AsyncResponse asyncResponse) {
        Collection<Part> parts;
        try {
            parts = request.getParts();
            executorPool.execute(new UploadThread(itsmcode, ticketid, attachmentid, parts, asyncResponse));
        }
        catch (IOException | ServletException exp) {
            TraceableException.writeLog(ErrorCode.FILE_WRITE_FAILED, itsmcode + ":" + attachmentid, exp);
        }

    }

    /**
     * 附件上传
     */
    private class UploadThread extends Thread {
        Collection<Part> parts;
        AsyncResponse asyncResponse;
        String itsmcode, ticketid, attachmentid;

        public UploadThread(String itsmcode, String ticketid, String attachmentid, Collection<Part> parts,
                            AsyncResponse asyncResponse) {
            this.parts = parts;
            this.asyncResponse = asyncResponse;
            this.itsmcode = itsmcode;
            this.attachmentid = attachmentid;
            this.ticketid = ticketid;
        }

        public void run() {
            try {
                RestResponse<Integer> response = new RestResponse<Integer>(ErrorCode.COMM_ERROR.getCode(), "Unknow",
                    -1);
                for (Part part : parts) {
                    //                    String header = part.getHeader("content-disposition");
                    String fileName = getFileName(itsmcode, ticketid, attachmentid);
                    if (Objects.nonNull(part.getContentType()) && CommonUtil.nonNullAndEmpty(fileName)) {
                        String fileServerType = PropertiesUtil.getStringValue("file.server.type", "local");
                        IFileService fileService = null;
                        if (fileServerType.equalsIgnoreCase("local")) {
                            fileService = new FileSystemService(PropertiesUtil.getAttributeBean());
                        }
                        else {
                            fileService = new FTPService(PropertiesUtil.getAttributeBean());
                        }
                        Tuple.Pair<String, Long> result = fileService.writeFile(
                            itsmcode + "/" + ticketid + "/" + attachmentid + "-" + fileName, part.getInputStream());
                        part.getInputStream().close();

                        String engnieer = (Objects.isNull(appsession) ? "test"
                            : appsession.getLoginData().getLoginname());

                        //更新附件信息到附件表
                        AttachmentVO attachmentVO = new AttachmentVO();
                        attachmentVO.setSubmitter(engnieer);
                        attachmentVO.setStatus(AttachmentPO.AttachmentStatus.UPLOADED.ordinal());
                        attachmentVO.setPath(result.getOne());
                        String rootPath = PropertiesUtil.getAttributeBean().getAttribute("cdn.path", "");
                        if (rootPath.endsWith("/"))
                            attachmentVO
                                .setUrl(rootPath + itsmcode + "/" + ticketid + "/" + attachmentid + "-" + fileName);
                        else
                            attachmentVO.setUrl(
                                rootPath + "/" + itsmcode + "/" + ticketid + "/" + attachmentid + "-" + fileName);

                        RestClientProxy clientProxy = RestClientFactory.getItsmGatewayClient();
                        IItsmTicket itsmTicket = clientProxy.getService(IItsmTicket.class);
                        response = itsmTicket.updateAttachment(itsmcode, ticketid, attachmentid, attachmentVO);
                    }
                }
                asyncResponse.resume(Response.ok(response).build());
            }
            catch (Exception exp) {
                TraceableException.writeLog(ErrorCode.FILE_WRITE_FAILED, itsmcode + ":" + attachmentid, exp);
            }
        }
    }

    /**
     * 从itsm获取附件文件名
     * @param header
     * @return
     */
    private String getFileName(String itsmCode, String ticketid, String attachmentid) {
        try {
            RestClientProxy clientProxy = RestClientFactory.getItsmGatewayClient();
            IItsmTicket itsmTicket = clientProxy.getService(IItsmTicket.class);
            RestResponse<AttachmentVO> response = itsmTicket.getAttachment(itsmCode, ticketid, attachmentid);
            return response.getResult().getName();
        }
        catch (Exception exp) {
            log.error("ticket {} attachment {} get name failed.", ticketid, attachmentid);
        }
        return null;
    }

}
